package com.codi.fcloud.ufx;

import com.codi.base.util.DateUtil;
import com.codi.base.util.StringUtil;
import com.codi.bus.constant.GlobalConstant;
import com.codi.fcloud.ufx.constant.HSOutputParameterNames;
import com.codi.trade.response.BaseHsResponse;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 模块名
 *
 * @author shi.pengyan
 * @version 1.0 2017-09-22 10:41
 * @since 1.0
 */
@Slf4j
public final class HsUtil {

    public static final Integer CLIENT_NAME_MAX_LENGTH = 20;

    public static String getClientName(String client_name) {
        return subStr(client_name, CLIENT_NAME_MAX_LENGTH);
    }

    public static final Integer CLIENT_FULL_NAME_MAX_LENGTH = 60;

    public static String getClientFullName(String client_full_name) {
        return subStr(client_full_name, CLIENT_FULL_NAME_MAX_LENGTH);
    }


    /**
     * 根据恒生计算 </br>
     * 中文算两个字符
     *
     * @param str
     * @param length
     * @return
     */
    public static String subStr(String str, int length) {
        int size = length(str);
        if (size <= length) {
            return str;
        }


        byte[] bytes;
        try {
            bytes = str.getBytes("Unicode");
            int n = 0; // 表示当前的字节数
            int i = 2; // 要截取的字节数，从第3个字节开始
            for (; i < bytes.length && n < length; i++) {
                // 奇数位置，如3、5、7等，为UCS2编码中两个字节的第二个字节
                if (i % 2 == 1) {
                    n++; // 在UCS2第二个字节时n加1
                } else {
                    // 当UCS2编码的第一个字节不等于0时，该UCS2字符为汉字，一个汉字算两个字节
                    if (bytes[i] != 0) {
                        n++;
                    }
                }
            }
            // 如果i为奇数时，处理成偶数
            if (i % 2 == 1) {
                // 该UCS2字符是汉字时，去掉这个截一半的汉字
                if (bytes[i - 1] != 0)
                    i = i - 1;
                    // 该UCS2字符是字母或数字，则保留该字符
                else
                    i = i + 1;
            }

            return new String(bytes, 0, i, "Unicode");
        } catch (UnsupportedEncodingException e) {
            log.error("fail to encoding", e);
        }
        return "";
    }

    /**
     * 统一用双字节长度
     *
     * @param str
     * @return
     */
    public static int length(String str) {
        if (str == null) {
            return 0;
        }
        str = str.replaceAll("[^\\x00-\\xff]", "**");
        return str.length();
    }


    /**
     * List<String,Object>  --> List<T>
     *
     * @param source
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> convertList(Map<String, Object> source, Class<T> clazz) {
        log.info("hundsun request={}", source);

        List<T> ret = new ArrayList<>();

        // 转换， 这一步强制转换是没有问题的，因为放入map时就是这个类型
        List<Map<String, Object>> list = (List<Map<String, Object>>) source.get(GlobalConstant.KEY_LIST_MAP);


        if (list != null) {
            for (Map<String, Object> map : list) {
                try {

                    if (isMapFail(map)) {
                        continue;
                    }

                    T obj = (T) clazz.newInstance();
                    BeanUtils.populate(obj, map);

                    ret.add(obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        return ret;
    }


    /**
     * Map转Obj
     *
     * @param source
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T convertMap(Map<String, Object> source, Class<T> clazz) {
        log.info("hundsun request={}", source);

        try {
            Map<String, Object> response = (Map<String, Object>) source.get(GlobalConstant.KEY_RESPONSE_RAW);

            T obj = (T) clazz.newInstance();

            if (isMapFail(source)) {
                log.warn("source map is failed. plz check.");

                if (obj instanceof BaseHsResponse) {
                    BaseHsResponse hsResponse = (BaseHsResponse) obj;
                    hsResponse.setSuccess(false);
                    hsResponse.setErrorCode(response.get(HSOutputParameterNames.ERROR_CODE).toString());
                    hsResponse.setErrorMessage(response.get(HSOutputParameterNames.ERROR_INFO).toString());
                }

                return obj;
            }

            log.debug("respones={}", response);
            BeanUtils.populate(obj, response);
            log.debug("obj={}", obj);

            if (obj instanceof BaseHsResponse) {
                BaseHsResponse hsResponse = (BaseHsResponse) obj;
                hsResponse.setSuccess(true);
            }

            log.info("beanutils populate suc");
            return obj;
        } catch (Exception e) {
            log.error("fail to convert to map", e);
        }

        log.error("return null");
        return null;
    }


    private static boolean isMapFail(Map<String, Object> map) {
        boolean isFail = false;

        // 不能使用error_code来判断，查询不出数据时error_cde也不为空
        // "error_info":"HS_QUERY-9K: 总记录数为0!"
        // {"error_code":"1000","error_info":"HS_QUERY-34:总记录数为0","success_type":"0"}
        // {"data":[{"success_type":"1","e-contract_flag":"","error_code":"1000","error_info":"返回记录长度小于349","fund_code":"","fund_name":""
        /*
         * 0-成功 1-系统级错误 2-应用级错误 3-业务级错误
         */
        if (map.containsKey(HSOutputParameterNames.SUCCESS_TYPE)
            && map.get(HSOutputParameterNames.SUCCESS_TYPE) != null) {
            String successType = map.get(HSOutputParameterNames.SUCCESS_TYPE).toString();
            if (!StringUtil.isEmpty(successType) && !successType.equals("0")) {
                isFail = true;
            }
        }

        // {"error_code":"1","error_info":"转发错误","error_no":"1"}
        if (!isFail && map.containsKey(HSOutputParameterNames.ERROR_NO)
            && map.get(HSOutputParameterNames.ERROR_NO) != null) {
            String errorNo = map.get(HSOutputParameterNames.ERROR_NO).toString();
            if (!StringUtil.isEmpty(errorNo)) {
                isFail = true;
            }
        }

        if (isFail) {

            String errorMessage = "";
            if (map.containsKey(HSOutputParameterNames.ERROR_INFO)
                && map.get(HSOutputParameterNames.ERROR_INFO) != null) {
                errorMessage = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            }



            log.error("fail to parse to bean,{}", errorMessage);
//            result.setSuccess(false);
//            result.setErrorType(GlobalConstant.ERROR_TYPE_SYSTEM);
//            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
//            result.setErrorMessage(errorMessage);

        }

        return isFail;
    }


    public static Date parseDate8(String dateStr) {
        if (Strings.isNullOrEmpty(dateStr)) {
            log.error("恒生返回日期格式异常{}", dateStr);
            return null;
        }

        try {
            return DateUtil.parse(dateStr, "yyyyMMdd");
        } catch (Exception e) {
            log.error("转换异常", e);
        }

        log.error("恒生返回日期转换异常{}", dateStr);
        return null;
    }


    public static BigDecimal parseNumber(String numberStr) {
        if (Strings.isNullOrEmpty(numberStr)) {
            log.warn("返回金额为空");
            return null;
        }

        try {
            return new BigDecimal(numberStr);
        } catch (Exception e) {
            log.error("金额转换异常", e);
        }
        log.error("金额转换异常{}", numberStr);
        return null;
    }

}
